001 package net.sf.xdc.util;
002
003 /*
004 * Copyright 2005-2006 Jens Voß.
005 *
006 * Licensed under the GNU Lesser General Public License (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://opensource.org/licenses/lgpl-license.php
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 import java.io.IOException;
020 import java.io.InputStream;
021 import java.io.Writer;
022 import java.util.Iterator;
023 import java.util.SortedSet;
024 import java.util.StringTokenizer;
025 import java.util.TreeSet;
026 import javax.xml.parsers.DocumentBuilderFactory;
027 import javax.xml.parsers.ParserConfigurationException;
028
029 import org.apache.xml.serialize.DOMSerializer;
030 import org.apache.xml.serialize.OutputFormat;
031 import org.apache.xml.serialize.Serializer;
032 import org.apache.xml.serialize.SerializerFactory;
033 import org.w3c.dom.Document;
034 import org.w3c.dom.Element;
035 import org.w3c.dom.NamedNodeMap;
036 import org.w3c.dom.Node;
037 import org.w3c.dom.NodeList;
038 import org.xml.sax.InputSource;
039 import org.xml.sax.SAXException;
040
041 /**
042 * This is a utility class responsible for parsing and printing XML documents.
043 *
044 * @author Jens Voß
045 * @since 0.5
046 * @version 0.5
047 */
048 public class XmlUtils {
049
050 private static final OutputFormat OF_XML = new OutputFormat();
051 private static final OutputFormat OF_HTML = new OutputFormat();
052 private static final DocumentBuilderFactory FACTORY = DocumentBuilderFactory.newInstance();
053
054 static {
055 OF_XML.setIndenting(true);
056 OF_XML.setIndent(2);
057 OF_XML.setEncoding("ISO-8859-1");
058 OF_XML.setPreserveSpace(false);
059 OF_HTML.setIndenting(true);
060 OF_HTML.setIndent(2);
061 OF_HTML.setEncoding("ISO-8859-1");
062 OF_HTML.setPreserveSpace(false);
063 OF_HTML.setStandalone(true);
064 }
065
066 /**
067 * This method creates a new DOM document.
068 *
069 * @return A new DOM document
070 * @throws XmlException
071 */
072 public static Document createDocument () throws XmlException {
073 try {
074 return FACTORY.newDocumentBuilder().newDocument();
075 }
076 catch (ParserConfigurationException e) {
077 throw new XmlException(e);
078 }
079 }
080
081 private static DOMSerializer getDOMSerializer (Writer out,
082 String method) throws IOException {
083 if ("html".equals(method)) {
084 return new XdcSerializer(out, OF_HTML);
085 }
086 // otherwise, i.e. for non-html output formats:
087 SerializerFactory sf = SerializerFactory.getSerializerFactory(method);
088 Serializer ser = sf.makeSerializer(out, OF_XML);
089 return ser.asDOMSerializer();
090 }
091
092 private static void print (Writer out,
093 Document doc,
094 String method) throws IOException {
095 getDOMSerializer (out, method).serialize(doc);
096 }
097
098 /**
099 * This method streams an XML document with method="html" into a
100 * <code>Writer</code> object.
101 *
102 * @param out The <code>Writer</code> object to which the contents of the
103 * document are written.
104 * @param doc The XML document to be streamed to the <code>Writer</code>
105 * @throws IOException
106 */
107 public static void printHtml (Writer out,
108 Document doc) throws IOException {
109 print(out, doc, "html");
110 }
111
112 /**
113 * This method streams an XML document with method="xml" into a
114 * <code>Writer</code> object.
115 *
116 * @param out The <code>Writer</code> object to which the contents of the
117 * document are written.
118 * @param doc The XML document to be streamed to the <code>Writer</code>
119 * @throws IOException
120 */
121 public static void printXml (Writer out,
122 Document doc) throws IOException {
123 print(out, doc, "xml");
124 }
125
126 /**
127 * This method creates an XML document from the contents of an
128 * <code>InputStream</code>.
129 *
130 * @param in The <code>InputStream</code> parsed by this method
131 * @return An XML <code>Document</code> object with the contents of the
132 * <code>InputStream</code>
133 * @throws XmlException
134 */
135 public static Document parse(InputStream in) throws XmlException {
136 try {
137 InputSource source = new InputSource(in);
138 return FACTORY.newDocumentBuilder().parse(source);
139 }
140 catch (SAXException e) {
141 throw new XmlException(e);
142 }
143 catch (IOException e) {
144 throw new XmlException(e);
145 }
146 catch (ParserConfigurationException e) {
147 throw new XmlException(e);
148 }
149 }
150
151 /**
152 * This method is the Java equivalent to the template with
153 * <code>mode="util.getLink"</code> defined in the <code>util.xsl</code>
154 * stylesheet. It creates a name for an XML element which can be used for
155 * interlinking parts of the documentation. Unlike the links between
156 * element summary descriptions and their detailed descriptions (which are
157 * created by simply numbering the nodes in the order of occurrence),
158 * this template creates a name from all the element's attributes by
159 * concatenating the element name with a sequence of all attribute names
160 * and values, separated by a tilde (~), with the attribute names sorted
161 * alphabetically and blanks in the attribute values omitted.<br/>
162 * Example: The return value of this template for a the element<br/>
163 * <code> <myNode yourAttr="attr one" ourAttr="attr two"/></code><br/>
164 * is
165 * <code> myNode~outAttr~attrtwo~yourAttr~attrone</code>
166 *
167 * @param node The DOM <code>Node</code> for which the link name is
168 * to be constructed
169 * @return The link name of the given DOM <code>Node</code>
170 */
171 public static String getLink(Element node) {
172 StringBuffer retVal = new StringBuffer(node.getNodeName());
173 StringBuffer attributeString = new StringBuffer();
174 NamedNodeMap attributes = node.getAttributes();
175 SortedSet attributeStrings = new TreeSet();
176 int num = attributes.getLength();
177 for (int i = 0; i < num; i++) {
178 Node attribute = attributes.item(i);
179 attributeString.setLength(0);
180 attributeString.append(attribute.getNodeName()).append('~');
181 String val = attribute.getNodeValue();
182 for (StringTokenizer tok = new StringTokenizer(val, " ", false); tok.hasMoreTokens();) {
183 attributeString.append(tok.nextToken());
184 }
185 attributeStrings.add(attributeString.toString());
186 }
187 for (Iterator iterator = attributeStrings.iterator(); iterator.hasNext();) {
188 retVal.append('~').append((String) iterator.next());
189 }
190 return retVal.toString();
191 }
192
193 /**
194 * This utility method retrieves the text value from a DOM <code>Node</code>.
195 *
196 * @param node The node whose text value is to be retrieved
197 * @return The given <code>Node</code>'s text value
198 */
199 public static String getTextValue(Node node) {
200 StringBuffer retVal = new StringBuffer();
201 NodeList children = node.getChildNodes();
202 for (int i = 0; i < children.getLength(); i++) {
203 retVal.append(children.item(i).getNodeValue());
204 }
205 return retVal.toString();
206 }
207
208 private XmlUtils() {
209 }
210
211 }